package cn.morge.springbootquartz.config;

import org.quartz.spi.JobFactory;
import org.quartz.spi.TriggerFiredBundle;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.quartz.SchedulerFactoryBean;
import org.springframework.scheduling.quartz.SpringBeanJobFactory;

import javax.sql.DataSource;

/**
 * @author 麻贵海
 * 创建时间:2018/08/05 17:40
 * 项目名称:esim
 * @version 1.0
 * @since JDK 1.8
 * 类说明: quartz 定时任务配置
 */
@Configuration
@EnableScheduling
public class QuartzConfiguration {

    /**
     * 继承自org.springframework.scheduling.quartz.SpringBeanJobFactory 实现任务实例化方式
     */
    public static class AutowiringSpringBeanJobFactory extends SpringBeanJobFactory implements ApplicationContextAware {

        private transient AutowireCapableBeanFactory beanFactory;

        @Override
        public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
            beanFactory = applicationContext.getAutowireCapableBeanFactory();
        }

        /**
         * 将Job实例给Spring IOC托管，我们在job实例实现类内可以直接使用spring注入的调用被spring ioc管理的实例
         *
         * @param bundle
         * @return
         * @throws Exception
         */
        @Override
        protected Object createJobInstance(TriggerFiredBundle bundle) throws Exception {
            final Object job = super.createJobInstance(bundle);
            // 将 Job的实例交给Spring IOC
            beanFactory.autowireBean(job);
            return job;
        }

        /**
         * 配置任务工厂实例
         *
         * @param context
         * @return
         */
        @Bean
        public JobFactory jobFactory(ApplicationContext context) {
            // 采用自定义工厂，整合Spring实例来完成构建任务
            AutowiringSpringBeanJobFactory jobFactory = new AutowiringSpringBeanJobFactory();
            jobFactory.setApplicationContext(context);
            return jobFactory;
        }

        /**
         * 配置任务调度器，使用项目数据源作为项目数据源
         *
         * @param jobFactory
         * @param dataSource
         * @return
         */
        @Bean
        public SchedulerFactoryBean schedulerFactoryBean(JobFactory jobFactory, DataSource dataSource) {
            SchedulerFactoryBean schedulerFactoryBean = new SchedulerFactoryBean();
            // 将Spring管理job自定义工厂交由调度器维护
            schedulerFactoryBean.setJobFactory(jobFactory);
            // 设置已存在的任务
            schedulerFactoryBean.setOverwriteExistingJobs(true);
            // 项目启动成功后等待2s开始执行调度器初始化
            schedulerFactoryBean.setStartupDelay(2);
            // 设置调度器自动运行
            schedulerFactoryBean.setAutoStartup(true);
            // 设置数据源，使用与项目统一数据源
            schedulerFactoryBean.setDataSource(dataSource);
            // 设置上下文，Spring bean name
            schedulerFactoryBean.setApplicationContextSchedulerContextKey("applicationContext");
            // 设置配置文件位置
            schedulerFactoryBean.setConfigLocation(new ClassPathResource("/quartz.properties"));

            return schedulerFactoryBean;
        }
    }
}
